package ru.pb.game.network.engine.client;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.log4j.Logger;

import ru.pb.game.network.clients.GameClient;
import ru.pb.game.network.engine.client.packets.FromClientToGameServerPacket;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BASE_ENTER_CHANNELSELECT_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BASE_ENTER_PROFILE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BASE_LEAVE_PROFILE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BASE_USER_ENTER_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BASE_USER_LEAVE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_ENDBATTLE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_GIVEUPBATTLE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_PRESTARTBATTLE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_READYBATTLE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_STARTBATTLE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_BATTLE_TIMERSYNC_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_CS_CLAN_LOGIN_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_CS_CLAN_LOGOUT_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_INVENTORY_ENTER_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_INVENTORY_LEAVE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_CHATTING_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_CREATE_NICK_NAME_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_CREATE_ROOM_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_ENTER_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_GET_PLAYERINFO_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_GET_ROOMINFO_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_GET_ROOMLIST_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_JOIN_ROOM_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_LOBBY_LEAVE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_ROOM_CHANGE_TEAM_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_ROOM_CLOSE_SLOT_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_ROOM_GET_LOBBY_USER_LIST_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_ROOM_HOST_CHANGE_TEAM_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_SERVER_MESSAGE_ANNOUNCE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_SHOP_ENTER_REQ;
import ru.pb.game.network.engine.client.packets.receivable.PROTOCOL_SHOP_LEAVE_REQ;
import ru.pb.game.network.engine.client.packets.receivable.SHOP_LIST_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_1310_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_1416_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_1445_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_1447_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_1451_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_2563_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_2584_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3587_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3591_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3593_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3608_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3650_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3853_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3855_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3860_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3870_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3872_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3890_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_3906_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_530_BUY_ITEM_REQ;
import ru.pb.game.network.engine.client.packets.receivable.opcode_544_REQ;
import ru.pb.global.network.engine.buffer.NioBuffer;
import ru.pb.global.network.engine.core.emuns.ConnectionState;
import ru.pb.global.network.engine.core.interfaces.IPacketHandler;
import ru.pb.global.network.utils.NetworkUtil;

/**
 * Слушает пакеты от игроков Сервера.
 * 
 * @author Felixx
 */
public class ClientsPacketListenerHandler implements IPacketHandler<GameClient>
{
	private static final Logger _log = Logger.getLogger(ClientsPacketListenerHandler.class);
	private boolean _aviableConnections = true;

	@Override
	public FromClientToGameServerPacket handle(NioBuffer buf, GameClient client)
	{
		boolean SHOW_ALL_PACKET = false;
		if(SHOW_ALL_PACKET)
		{
			NioBuffer temp = buf;
			int allSize = temp.limit();
			int position = temp.position();
			int opcode = temp.getUnsignedShort();
			_log.info("Packet id: " + opcode + "; size: " + allSize + "; pos:" + position);
		}

		ConnectionState state = client.getState();
		int opcode = buf.getUnsignedShort();
		FromClientToGameServerPacket packet = null;

		if(_aviableConnections)
		{
			switch(state)
			{
				case CONNECTED:
				{
					switch(opcode)
					{
						case 544:
						{
							// Активация окна с игрой.
							// _log.info("========================================");
							// _log.info(NetworkUtil.printData(buf));
							// _log.info("========================================");
							packet = new opcode_544_REQ();
							break;
						}
						case 2653:
						{
							// Выход с игры.
							packet = new opcode_2563_REQ();
							break;
						}
						case 2579:
						{
							// Вход на гейм сервер =)
							packet = new PROTOCOL_BASE_USER_ENTER_REQ();
							break;
						}
						case 2571:
						{
							packet = new PROTOCOL_BASE_ENTER_CHANNELSELECT_REQ();
							break;
						}
						case 2573:
						{
							packet = new PROTOCOL_SERVER_MESSAGE_ANNOUNCE_REQ();
							break;
						}
						case 2817:
						{
							packet = new PROTOCOL_LOBBY_ENTER_REQ();
							break;
						}
						case 2575:
						{
							// Что то вроде обновления информации о сервере(пакет шлет клиент 1 раз в минуту).
							// Хер его знает надо ли обновлять, может оно как в ЛС. с оффа пойматоь не магу.
							// _log.info("Хочу обновить информацию о серваках, state: " + state);
							// packet = new PROTOCOL_BASE_ENTER_CHANNELSELECT_REQ();
							break;
						}
						case 2577:
						{
							packet = new PROTOCOL_BASE_USER_LEAVE_REQ();
							break;
						}
						case 2584:
						{
							packet = new opcode_2584_REQ();
							break;
						}
						case 2819: // Обновление информации о комнатах и списке ожидающих игроков.
						{
							packet = new PROTOCOL_LOBBY_GET_ROOMLIST_REQ();
							break;
						}
						case 2825: // Создание комнаты.
						{
							_log.info("========================================");
							_log.info(NetworkUtil.printData(buf));
							_log.info("========================================");
							packet = new PROTOCOL_LOBBY_CREATE_ROOM_REQ();
							break;
						}
						case 2827: // Вход в комнату
						{
							packet = new PROTOCOL_LOBBY_JOIN_ROOM_REQ();
							break;
						}
						case 2627: // Общий чат. Ещщо: 1358 и 1576 и 1390
						{
							packet = new PROTOCOL_LOBBY_CHATTING_REQ();
							break;
						}
						case 2829: // EXIT_LOBBY
						{
							packet = new PROTOCOL_LOBBY_LEAVE_REQ();
							break;
						}
						case 3329:
						{
							// SHOP_IN
							// _log.info("=== INTER TO SHOP === ");
							packet = new PROTOCOL_SHOP_ENTER_REQ();
							break;
						}
						case 3331:
						{
							// SHOP_OUT
							// _log.info("=== LEAVE FROM SHOP === ");
							packet = new PROTOCOL_SHOP_LEAVE_REQ();
							break;
						}
						case 3333:
						{
							// Магазин - список предметов
							packet = new SHOP_LIST_REQ();
							// _log.info(NetworkUtil.printData(buf));
							break;
						}
						case 3073:
						{
							// INVENTORY_IN
							packet = new PROTOCOL_INVENTORY_ENTER_REQ();
							break;
						}
						case 3075:
						{
							// INVENTORY_OUT
							packet = new PROTOCOL_INVENTORY_LEAVE_REQ();
							break;
						}
						case 3591: // Изменение настроек разрешонного оружия.
						{
							packet = new opcode_3591_REQ();
							break;
						}
						case 3593: // Изменение пароля в комнате
						{
							packet = new opcode_3593_REQ();
							break;
						}
						case 3600:
						{
							// CHANGE_TEAM
							packet = new PROTOCOL_ROOM_CHANGE_TEAM_REQ();
							break;
						}
						case 3622:
						{
							packet = new PROTOCOL_ROOM_HOST_CHANGE_TEAM_REQ();
							break;
						}
						case 3610:
						{
							// Profile enter
							packet = new PROTOCOL_BASE_ENTER_PROFILE_REQ();
							break;
						}
						case 3612:
						{
							// Profile leave
							packet = new PROTOCOL_BASE_LEAVE_PROFILE_REQ();
							break;
						}
						case 3650:
						{
							packet = new opcode_3650_REQ();
							break;
						}
						case 3843:
						{
							// Подготовка к бою
							packet = new PROTOCOL_BATTLE_READYBATTLE_REQ();
							break;
						}
						case 3845:
						{
							packet = new PROTOCOL_BATTLE_PRESTARTBATTLE_REQ();
							break;
						}
						case 3849:
						{
							packet = new PROTOCOL_BATTLE_ENDBATTLE_REQ();
							break;
						}
						case 3847:
						{
							packet = new PROTOCOL_BATTLE_STARTBATTLE_REQ();
							break;
						}
						case 3595:
						{
							packet = new PROTOCOL_ROOM_CLOSE_SLOT_REQ();
							break;
						}
						case 1441:
						{
							// CLAN_IN
							packet = new PROTOCOL_CS_CLAN_LOGIN_REQ();
							break;
						}
						case 1443:
						{
							// CLAN_OUT
							packet = new PROTOCOL_CS_CLAN_LOGOUT_REQ();
							break;
						}
						case 1445:
						{
							// Список кланов
							packet = new opcode_1445_REQ();
							break;
						}
						case 2831:
						{
							// Создание перса(ввод никнейма)
							packet = new PROTOCOL_LOBBY_CREATE_NICK_NAME_REQ();
							break;
						}
						case 3892:
						{
							// Возрождение ботов.
							packet = new PROTOCOL_BATTLE_GIVEUPBATTLE_REQ();
							break;
						}
						case 2835:
						{
							// Получаем инфу о комнате.
							packet = new PROTOCOL_LOBBY_GET_ROOMINFO_REQ();
							break;
						}
						case 1416:
						{
							// создание клана(токо ник)
							packet = new opcode_1416_REQ();
							break;
						}
						case 3853:
						{
							packet = new opcode_3853_REQ();
							break;
						}
						case 3860:
						{
							packet = new opcode_3860_REQ();
							break;
						}

						case 3884:
						{
							packet = new PROTOCOL_BATTLE_TIMERSYNC_REQ();
							break;
						}
						case 3855:
						{
							packet = new opcode_3855_REQ();
							break;
						}
						case 3890:
						{
							packet = new opcode_3890_REQ();
							break;
						}
						case 2638: // Информация по статистике игроков в лобби
						{
							packet = new PROTOCOL_LOBBY_GET_PLAYERINFO_REQ();
							break;
						}
						case 3608: // Сохранение настроек комнаты всех, кроме мапы, типа игры, и условий, а также пароля и названия комнаты
						{
							packet = new opcode_3608_REQ();
							break;
						}
						case 3602:
						{
							packet = new PROTOCOL_ROOM_GET_LOBBY_USER_LIST_REQ();
							break;
						}
						case 3870:
						{
							packet = new opcode_3870_REQ();
							break;
						}
						case 3872:
						{
							packet = new opcode_3872_REQ();
							break;
						}
						case 3906:
						{
							packet = new opcode_3906_REQ();
							break;
						}
						case 3587:
						{
							packet = new opcode_3587_REQ();
							break;
						}
						case 1451:
						{
							packet = new opcode_1451_REQ();
							break;
						}
						case 2581: // Пакет сохранения настроек
						{
							// packet = new opcode_2581_REQ();
							break;
						}
						case 530:
						{
							packet = new opcode_530_BUY_ITEM_REQ();
							break;
						}
						case 1447:
						{
							packet = new opcode_1447_REQ();
							break;
						}
						case 1310:
						{
							packet = new opcode_1310_REQ();
							break;
						}
						default:
						{
							debugOpcode(opcode, state, client, buf);
						}
					}
					break;
				}
			}
			return packet;
		}
		return null;
	}

	private void debugOpcode(int opcode, ConnectionState state, GameClient client, NioBuffer buf)
	{
		try
		{
			_log.info("Unknown Opcode: " + opcode + " for state: " + state.name() + " from IP: " + client.getIPString());
			FileWriter WR = new FileWriter(createFile("UNK_OPCODE_" + opcode, "txt"));
			NioBuffer temp = buf;
			temp.position(0);
			String SS = NetworkUtil.printData(temp);
			WR.write(SS);
			WR.close();
			_log.info(SS);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private static File createFile(String name, String r) throws Exception
	{
		File file = new File("./" + name + "." + r);
		if(file.exists())
			file.delete();
		file.createNewFile();
		return file;
	}
}